package com.order.app;

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author xiangminwen
 * @date 2024/11/25 16:21
 */
public class LockBasedQueue {

    private final Queue<Object> queue = new LinkedList<>();
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition notEmpty = lock.newCondition();
    private final Condition notFull = lock.newCondition();

    public void put(Object element) throws InterruptedException {
        lock.lockInterruptibly();
        try {
            while (queue.size() == 2) { // 假设队列大小为2
                //持有Lock的线程中调用await()允许其他线程来抢夺锁当前锁
                System.out.println("xxx");
                notFull.await();
            }
            queue.offer(element);
            notEmpty.signal();
        } finally {
            lock.unlock();
        }
    }

    public Object take() throws InterruptedException {
        lock.lockInterruptibly();
        try {
            while (queue.isEmpty()) {
                notEmpty.await();
            }
            Object element = queue.poll();
            notFull.signal();
            return element;
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        LockBasedQueue basedQueue = new LockBasedQueue();
        new Thread(() -> {
            try {
                basedQueue.put("22221");
                basedQueue.put("22221");
            } catch (InterruptedException ignored) {
            }
        }, "t1").start();

        new Thread(() -> {
            try {
                basedQueue.put("22222");
                basedQueue.put("22222");
            } catch (InterruptedException ignored) {
            }
        }, "t2").start();

        new Thread(() -> {
            try {
                basedQueue.put("22223");
                basedQueue.put("22223");
            } catch (InterruptedException ignored) {
            }
        }, "t3").start();
        TimeUnit.SECONDS.sleep(1);

        new Thread(() -> {
            try {
                System.out.println(basedQueue.take());
            } catch (InterruptedException ignored) {
            }
        }, "t4").start();
        TimeUnit.SECONDS.sleep(1);
        System.out.println(basedQueue.queue.size());

        new Thread(() -> {
            try {
                System.out.println(basedQueue.take());
                System.out.println(basedQueue.take());
                System.out.println(basedQueue.take());
                System.out.println(basedQueue.take());
                System.out.println(basedQueue.take());
            } catch (InterruptedException ignored) {
            }
        }, "t4").start();
        TimeUnit.SECONDS.sleep(1);
        System.out.println(basedQueue.queue.size());
    }
}
